package com.apes.fn.scm.retailOrder.service.account.retail;

import com.alibaba.fastjson.JSON;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.model.RetailOrderItem;
import com.apes.fn.scm.retailOrder.service.account.BackBatchAndSupplierService;
import com.apes.fn.scm.retailOrder.service.account.RetailAccountData;
import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.ReflectUtil;
import com.apes.scm.account.account.model.AccountingMethod;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.account.tax.service.TaxService;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.contract.service.ContractService;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherInventory;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherInventoryRepository;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.VoucherType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 外协代销带安逻辑处理
 *
 * @Author wuq
 * @Date 2021-9-13
 */
@RetailAccount(value = "retailOutHelp", name = "外协代销带安")
@Service
public class RetailOutHelpVoucherService extends BackBatchAndSupplierService {

    @Autowired
    private TaxService taxService;
    @Autowired
    private ContractService contractService;
    @Autowired
    private VoucherInventoryRepository voucherInventoryRepository;

    /**
     * 外协代销带安逻辑处理
     * 代销模式（寄售模式）：在寄售采购与寄售销售的时候，不写账单（销售的部分只是冻结批次），在实现销售的时候，根据寄售消耗凭证写账单
     *
     * @param retailAccountData RetailOrder
     */
    public void process(RetailAccountData retailAccountData) {
        RetailOrder retailOrder = retailAccountData.getRetailOrder();

        // 带安
        Map<Contract, List<RetailOrderItem>> outRetailOrderItems = retailOrder.getSaleItems()
                .stream()
                .filter(item -> item.getProductRule() == 10 && item.getSupplier() != null)
                .collect(Collectors.groupingBy(RetailOrderItem::getContract));

        outRetailOrderItems.forEach((contract, retailOrderItems) -> {
            // 判断合同公司与工单上面的公司是否一致
            if ("supplier".equals(contract.getContractType().getCode()) && !Objects.equals(contract.getCompany().getId(), retailOrder.getCompany().getId())) {
                // 找合同上面的所属公司做采购
                createOutCrossPurchaseVoucher(retailOrder, contract, retailOrderItems);
            } else {
                // 直接找供应商做采购
                createOutPurchaseVoucher(retailOrder, contract, retailOrderItems, false);
            }
        });
    }


    private void createOutPurchaseVoucher(RetailOrder retailOrder, Contract contract, List<RetailOrderItem> items, boolean isCross) {
        Voucher purVoucher = new Voucher();
        ReflectUtil.copy(retailOrder, purVoucher, "dept", "company", "scene");

        if (isCross) {  // 如果是跨公司，就需要找合同上面的公司做采购；非跨公司，就直接找真实供应商采购
            // 对合同上面的公司 经销
            purVoucher.setPartner(contract.getCompany().getParty().getPatyRoleByType("Supplier"));

            purVoucher.setInventoryMode(InventoryMode.IM_OWN);     //设置库存模式：自有
            purVoucher.setAccountingMethod(AccountingMethod.AM_PURCHASE);  // 核算方式：经销
        } else {
            // 对外部供应商 代销
            purVoucher.setContract(contract);
            purVoucher.setPartner(purVoucher.getContract().getPartner().getParty().getPatyRoleByType("Supplier"));
            purVoucher.setInventoryMode(contract.getCooperation().getInventoryMode());     //设置库存模式：寄售
            purVoucher.setAccountingMethod(contract.getCooperation().getAccountingMethod());  // 核算方式：采购价
        }

        purVoucher.setClassification(VoucherType.CONSIGNMENT_INSTALL);
        purVoucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());
        purVoucher.setClerk(retailOrder.getClerk()); //业务员

        purVoucher.setBusinessType(BusinessType.PURCHASE_ORDER);
        purVoucher.setOrigin(retailOrder.getId());
        purVoucher.setOriginBusinessType(retailOrder.getInnerBusinessType());
        purVoucher.setSource(retailOrder.getId());
        purVoucher.setSourceBusinessType(retailOrder.getInnerBusinessType());

        PartyRole supplier = purVoucher.getPartner();
        purVoucher.setVoucherItems(
                items.stream().map(
                        item -> {
                            VoucherItem voucherItem = new VoucherItem();

                            ReflectUtil.copy(item, voucherItem, "product", "uom");
                            voucherItem.setOwner(item.getOwner());

                            voucherItem.setInnerSalePriceUnit(item.getInnerSalePriceUnit());    // 公司间交易价
                            voucherItem.setPriceUnit(item.getInnerSalePriceUnit());     // 内部销售价
                            voucherItem.setProductQty(item.getProductUomQty());
                            voucherItem.setInventoryBatch(item.getInventoryBatch());    // 指定销售批次

                            voucherItem.setOriginItemId(item.getId());
                            voucherItem.setSourceItemId(item.getId());
                            voucherItem.setSupplier(item.getSupplier());
                            voucherItem.setOwner(retailOrder.getCompany());

                            voucherItem.setDiscount(0d);
                            Tax tax = taxService.getPurchaseTax(retailOrder.getCompany(), supplier, item.getProduct());   //供应商进项税
                            voucherItem.setTax(tax);
                            return voucherItem;
                        }
                ).collect(Collectors.toSet()));
        if (purVoucher.getVoucherItems().size() == 0) throw new RuntimeException("生成带安采购凭证时报错，没有采购凭证明细！");

        purVoucher = invoke("voucher.create", MapUtil.mapped(purVoucher));

        // 回写方案明细批次以及供应商信息
        sendRetailBathAndSupplier(items, purVoucher);

        // 存在内部销售为经销的，需要写账单
        if ("IM_OWN".equals(purVoucher.getInventoryMode())) {
            createInvoiceAndFixOriginNumber(retailOrder, purVoucher);
        }
    }


    private void createOutCrossPurchaseVoucher(RetailOrder retailOrder, Contract contract, List<RetailOrderItem> items) {
        // 分销单采购以及销售
        Voucher voucher = createCrossPurchaseVoucher(retailOrder, contract, items);
        createCrossSaleVoucher(voucher, items);

        // 对合同上面的公司生成带安采购凭证
        createOutPurchaseVoucher(retailOrder, contract, items, true);
    }

    /**
     * 合同公司对外部供应商采购
     * 这里是代销采购
     *
     * @param retailOrder      零售单
     * @param purContract      采购合同
     * @param retailOrderItems 零售单明细
     * @return 采购凭证
     */
    private Voucher createCrossPurchaseVoucher(RetailOrder retailOrder, Contract purContract, List<RetailOrderItem> retailOrderItems) {
        Voucher purVoucher = new Voucher();
        purVoucher.setBusinessType(BusinessType.PURCHASE_ORDER);
        purVoucher.setClerk(retailOrder.getClerk()); //业务员

        purVoucher.setDept(purContract.getDept());
        purVoucher.setCompany(purContract.getCompany());
        purVoucher.setPartner(purContract.getPartner().getParty().getPartyRoleByType("Supplier"));     // 外部供应商

        purVoucher.setCustomerExpand(retailOrder.getCustomerExpand().getId());
        purVoucher.setOrigin(retailOrder.getId());
        purVoucher.setOriginBusinessType(retailOrder.getInnerBusinessType());
        purVoucher.setSource(retailOrder.getId());
        purVoucher.setSourceBusinessType(retailOrder.getInnerBusinessType());

        purVoucher.setContract(purContract);
        purVoucher.setInventoryMode(purContract.getCooperation().getInventoryMode());     // 库存模式
        purVoucher.setAccountingMethod(purContract.getCooperation().getAccountingMethod());  // 核算方

        purVoucher.setVoucherItems(
                retailOrderItems.stream().map(
                        item -> {
                            VoucherItem voucherItem = new VoucherItem();
                            voucherItem.setProduct(item.getProduct());

                            // 设置为销售的单位以及数量
                            voucherItem.setUom(item.getUom());
                            voucherItem.setProductQty(item.getProductUomQty());

                            // 电池检测报告没有 OriginNumber
                            voucherItem.setOriginItemId(StringUtils.isEmpty(item.getOriginnumber()) ? item.getId() : item.getOriginnumber() );
                            voucherItem.setSourceItemId(item.getId());
                            voucherItem.setOwner(purContract.getCompany());

                            Tax tax = taxService.getPurchaseTax(purContract.getCompany(), item.getSupplier(), item.getProduct());   //供应商进项税
                            voucherItem.setTax(tax);
                            voucherItem.setSupplier(item.getSupplier());
                            voucherItem.setPriceUnit(item.getPriceOutUnitInTax());  // 采购价格取带安成本单价
                            voucherItem.setInnerSalePriceUnit(item.getInnerSalePriceUnit());    // 公司间交易价
                            return voucherItem;
                        }).collect(Collectors.toSet()));

        if (purVoucher.getVoucherItems().size() == 0) throw new RuntimeException("生成带安采购凭证时报错，没有采购凭证明细！");
        purVoucher = invoke("voucher.create", MapUtil.mapped(purVoucher));

        changeFrostQty(purVoucher, "零售单生成，代销带安采购凭证");
        return purVoucher;
    }

    /**
     * 内部结算使用经销的方式
     *
     * @param purVoucher       采购凭证
     * @param retailOrderItems 代销带安明细
     */
    private void createCrossSaleVoucher(Voucher purVoucher, List<RetailOrderItem> retailOrderItems) {
        RetailOrder retailOrder = retailOrderItems.get(0).getOrder();
        Voucher voucher = new Voucher();
        voucher.setBusinessType(BusinessType.SALE_ORDER);
        ReflectUtil.copy(purVoucher, voucher, "dept", "company", "clerk", "scene", "customerExpand");

        voucher.setPartner(retailOrder.getCompany().getParty().getPartyRoleByType("Customer"));     // 门店公司

        Contract contract = contractService.getContract(voucher.getDept(), voucher.getPartner(), "distribution", "customer", "零售单外协代销带安业务");  // 寄售合同
        voucher.setContract(contract);
        voucher.setInventoryMode(contract.getCooperation().getInventoryMode());     //设置库存模式
        voucher.setAccountingMethod(contract.getCooperation().getAccountingMethod());  // 核算方式

        voucher.setSource(purVoucher.getId());
        voucher.setSourceBusinessType(Voucher.class.getSimpleName());
        voucher.setOrigin(retailOrder.getId());
        voucher.setOriginBusinessType(RetailOrder.class.getSimpleName());

        voucher.setVoucherItems(
                retailOrderItems.stream().map(item -> {
                    VoucherItem voucherItem = new VoucherItem();
                    voucherItem.setProduct(item.getProduct());
                    voucherItem.setUom(item.getUom());

                    voucherItem.setProductQty(item.getProductUomQty());
                    voucherItem.setSourceItemId(item.getId());
                    voucherItem.setOriginItemId(item.getId());
                    voucherItem.setDiscount(0d);
                    voucherItem.setTax(voucherItem.getProduct().getTax());
                    voucherItem.setSupplier(purVoucher.getPartner());
                    voucherItem.setOwner(purVoucher.getCompany());

                    voucherItem.setPriceUnit(item.getInnerSalePriceUnit());

                    return voucherItem;
                }).collect(Collectors.toSet()));

        // 添加采购凭证批次以及供应商信息
        voucher.getVoucherItems().forEach(item -> {
            purVoucher.getVoucherItems().forEach(purchaseVoucherItem -> {

                VoucherInventory voucherInventory = voucherInventoryRepository.findByVoucherItem(purchaseVoucherItem).stream()
                        .findAny().orElseThrow(() -> new RuntimeException("找不到批次信息！"));

                if (item.getProduct().getId().equals(voucherInventory.getProduct().getId())) {
                    item.setInventoryBatch(voucherInventory.getInventoryBatch());
                    item.setSupplier(purchaseVoucherItem.getSupplier());
                }
            });
        });

        voucher = invoke("voucher.create", MapUtil.mapped(voucher));
        createInvoiceAndFixOriginNumber(retailOrder, voucher);
    }
}
